﻿using System;
using System.ServiceModel;
using nRoute.Components.Composition;
using Orktane.Components;
using Orktane.Sample.ConsoleApp.Services;
using Orktane.ScriptActionModel;
using System.Windows;

namespace Orktane.Sample.ConsoleApp.ScriptActions
{
    [MapScriptAction("GET-PROCESS", "Get Process", ShortDescription = "Get a list of processes on the remote machine",
        Lifetime = InstanceLifetime.PerInstance)]
    public class GetProcessScriptAction
        : IConsoleScriptAction
    {
        private const string ECLIPSE = "...";
        private const string SPACE = " ";

        private RemoteProcessesServiceClient _remoteProcessesService;
        private IConsole _console;
        private IDisposable _completionToken;

#region IConsoleScriptAction Members

        public void Intialize(IConsole console, IDisposable completionToken)
        {
            if (console == null) throw new ArgumentNullException("console");
            if (completionToken == null) throw new ArgumentNullException("completionToken");

            _console = console;
            _completionToken = completionToken;
        }

        public void Execute(Arguments args)
        {
            _remoteProcessesService = new RemoteProcessesServiceClient();
            _remoteProcessesService.GetRunningProcessesCompleted += new EventHandler<GetRunningProcessesCompletedEventArgs>(Service_GetRunningProcessesCompleted);
            _remoteProcessesService.GetRunningProcessesAsync(args != null ? args.CommandLine : null);

            _console.DisabledInputText = "Retrieving, please hold..";
            _console.DisableInput = true;
        }

        public bool Cancel()
        {
            if (_remoteProcessesService != null && 
                (_remoteProcessesService.State == CommunicationState.Opened || _remoteProcessesService.State == CommunicationState.Opening))
            {
                _remoteProcessesService.Abort();
            }

            _console.WriteLine("Cancelled Get-Process..");
            return true;
        }

        public void Close()
        {
            if (_remoteProcessesService != null)
            {
                if (_remoteProcessesService.State != CommunicationState.Closed && _remoteProcessesService.State != CommunicationState.Closing)
                {
                    _remoteProcessesService.CloseAsync();
                }
                _remoteProcessesService.GetRunningProcessesCompleted -= new EventHandler<GetRunningProcessesCompletedEventArgs>(Service_GetRunningProcessesCompleted);
            }

            _remoteProcessesService = null;
            _console.DisabledInputText = string.Empty;
            _console.DisableInput = false;
        }

#endregion

#region Handlers

        private void Service_GetRunningProcessesCompleted(object sender, GetRunningProcessesCompletedEventArgs e)
        {
            if (_remoteProcessesService == null) return;

            if (e.Cancelled == false && e.Error == null)
            {
                _console.WriteLine("---------------------------------------------------------------------------");
                _console.Write(PadOrConstrainString("P.ID", 8));
                _console.Write(PadOrConstrainString("MEMORY USE", 14));
                _console.WriteLine(PadOrConstrainString("PROCESS NAME", 56));
                _console.WriteLine("---------------------------------------------------------------------------");

                foreach (var _process in e.Result)
                {
                    var _processCurrent = _process;
                    Application.Current.RootVisual.Dispatcher.BeginInvoke(() =>
                    {
                        _console.Write(PadOrConstrainString(_processCurrent.ProcessId.ToString(), 8));
                        _console.Write(PadOrConstrainString(_processCurrent.WorkingMemorySize.ToString("###,###"), 14));
                        _console.WriteLine(PadOrConstrainString(_processCurrent.ProcessName, 56));
                    });
                }

                Application.Current.RootVisual.Dispatcher.BeginInvoke(() => _console.WriteLine());
            }
            else
            {
                if (e.Error != null)
                {
                    _console.Write("An Error Occurred: ");
                    _console.WriteLine(e.Error.Message);
                    _console.WriteLine();
                    _console.WriteLine(e.Error.StackTrace);
                }
                else
                {
                    _console.WriteLine("Script command was cancelled");
                }
            }

            // and indicate that we have completed
            _console.WriteLine();
            _completionToken.Dispose();
        }

#endregion

#region Helpers

        private static string PadOrConstrainString(string value, int length)
        {
            if (string.IsNullOrEmpty(value)) value = string.Empty;
            if (value.Length > length) return ConstrainString(value, length);

            // we add 
            var _addedLength = length - value.Length;
            for (var i = 0; i < _addedLength; i++)
            {
                value += SPACE;
            }
            return value;
        }

        private static string ConstrainString(string value, int length)
        {
            if (string.IsNullOrEmpty(value)) return string.Empty;
            return value.Length > length ? value.Substring(0, length - 3) + ECLIPSE : value;
        }

#endregion

    }
}
